/*
 * bjm.y
 *
 *  Created on: Jan 12, 2014
 *      Author: Benjamin Groeber, Julian Sanin, Matthaeus Ranigler
 */

%{

#include "bjm.h"
#include "nodes.h"
#include <stdio.h>
#include <stdlib.h>

void yyerror(char const *msg);
expTree root;

%}

/* YACC mappings. */
%union {
    float   floats;
    int     ints;
    int		type;
    char 	*sym;
    expTree exptree;
}

%start SCOPE
%token PRINT
%token QUIT
%token DECR INCR
%token LT LE EQ NE GT GE
%token IF ELSE
%token AND OR 
%token WHILE UNTIL
%token STARTSCOPE ENDSCOPE
%token <type> INT
%token <type> FLOAT
%token <ints> INTNUM
%token <floats> FLOATNUM
%token <sym> SYMBOL

%type <exptree> SCOPE TERM STATEMENT RELEXPR EXPR INCREMENT DECREMENT CONDITION CONDITIONAL ENDING ASSIGN LOOP DECLARE STMT_LIST

%left '+' '-'
%left '*' '/'
%left OR
%left AND
%right STARTSCOPE ELSE
%right DECR INCR
%right '('

%%

/* Language description and corresponding actions in C code. */

SCOPE	:  SCOPE STATEMENT 	{ ex($2); } 
		|  SCOPE QUIT ';'		{ quit(EXIT_SUCCESS); }	
		| QUIT ';'		{ quit(EXIT_SUCCESS); }	
		| /*NULL*/
		;
		
STATEMENT : DECLARE	';'		{ $$ = $1; }
		| ASSIGN	';'		{ $$ = $1; }
		| EXPR		';'		{ $$ = $1; }
		| CONDITION			{ $$ = $1; }
		| LOOP				{ $$ = $1; }
		| PRINT EXPR ';' 	{ $$= printExp($2); }
		;
		
STMT_LIST: STATEMENT 		{ $$ = $1; }
		|	STMT_LIST STATEMENT 	{$$ = multiStmt($1,$2);}
		
		;
		
CONDITION: IF '(' CONDITIONAL ')' STARTSCOPE ENDING		{ $$ = ifsExp(ifSt, $3,$6,$3); }
		|  IF '(' CONDITIONAL ')' STARTSCOPE STMT_LIST ELSE ENDING	{ $$ = ifsExp(elseSt, $3,$6,$8); }
		;

LOOP	: WHILE '(' CONDITIONAL ')' STARTSCOPE ENDING { $$ = loopsExp(whileLoop, $3,$6); }
		| UNTIL '(' CONDITIONAL ')' STARTSCOPE ENDING { $$ = loopsExp(untilLoop, $3,$6); }
		;

CONDITIONAL: RELEXPR			{ $$ = $1; }
		| CONDITIONAL OR RELEXPR {  $$ = boolExp(or, $1,$3); }
		| CONDITIONAL AND RELEXPR {  $$ = boolExp(and, $1,$3); }
		; 
	
ENDING	: STMT_LIST ENDSCOPE		{ $$ = $1; }
		;
		
DECLARE	: INT SYMBOL		{ $$ = opExp(ASI, idExp($2), conExp(IN, 0));  }
		| FLOAT SYMBOL		{ $$ = opExp(ASI, idExp($2), conExp(FN, 0));  }
		;
		
ASSIGN	:SYMBOL '=' EXPR	{ $$ = opExp(ASI, idExp($1), $3);  }
		|DECLARE '=' EXPR	{ $$ = opExp(ASI, $1, $3);  }
		;

EXPR	:TERM					{ $$ = $1; }
		| RELEXPR				{ $$ = $1; }
		| INCREMENT				{ $$ = $1; }
		| DECREMENT				{ $$ = $1; }
		| '(' EXPR ')'			{ $$ = $2; }
		| EXPR '+' EXPR			{ $$ = opExp(ADD, $1,$3); }
		| EXPR '-' EXPR			{ $$ = opExp(SUB, $1,$3);}
		| EXPR '*' EXPR			{ $$ = opExp(MUL, $1,$3); }
		| EXPR '/' EXPR			{ $$ = opExp(DIV, $1,$3); }
		| '!' EXPR				{ $$ = opExp(FCT, $2,$2); }
		;

RELEXPR	: RELEXPR LT EXPR		{ $$ = relopExp(lt, $1,$3); }
		| RELEXPR LE EXPR		{ $$ = relopExp(le, $1,$3); }
		| RELEXPR EQ EXPR		{ $$ = relopExp(eq, $1,$3); }
		| RELEXPR NE EXPR		{ $$ = relopExp(ne, $1,$3); }
		| RELEXPR GE EXPR		{ $$ = relopExp(ge, $1,$3); }
		| RELEXPR GT EXPR		{ $$ = relopExp(gt, $1,$3); }
		| EXPR					
		;
			
INCREMENT : SYMBOL INCR			{ $$ = opExp(INC,idExp($1),idExp($1)); }
		|	INTNUM INCR 		{ $$ = opExp(INC,conExp(IN,$1),conExp(IN,$1));}
		;
		
DECREMENT : SYMBOL DECR			{ $$ = opExp(DEC,idExp($1),idExp($1)); }
		|	INTNUM DECR 		{ $$ = opExp(DEC,conExp(IN,$1),conExp(IN,$1));}	
		;	
		
TERM	: INTNUM				{ $$ = conExp(IN, $1); }
		| FLOATNUM				{ $$ = conExp(FN, $1); }
		| SYMBOL				{ $$ = idExp($1); }
		;		

%%

/* Additional C code. */

// Called by yyparse on error.
void yyerror(char const *msg) {
	fprintf (stderr, "Error: %s\n", msg);
}

